<?php

namespace app\libs;

use think\facade\Db;
use think\facade\Cache;

/**
 * 权限认证类
 * 功能特性：
 * 1，是对规则进行认证，不是对节点进行认证。用户可以把节点当作规则名称实现对节点进行认证。
 *      $auth=new Auth();  $auth->check('规则名称','用户id')
 * 2，可以同时对多条规则进行认证，并设置多条规则的关系（or或者and）
 *      $auth=new Auth();  $auth->check('规则1,规则2','用户id','and')
 *      第三个参数为and时表示，用户需要同时具有规则1和规则2的权限。 当第三个参数为or时，表示用户值需要具备其中一个条件即可。默认为or
 * 3，一个用户可以属于多个用户组(think_auth_group_access表 定义了用户所属用户组)。我们需要设置每个用户组拥有哪些规则(admin_auth_group 定义了用户组权限)
 *
 * 4，支持规则表达式。
 *      在admin_auth_rule 表中定义一条规则时，如果type为1， condition字段就可以定义规则表达式。 如定义{score}>5  and {score}<100  表示用户的分数在5-100之间时这条规则才会通过。
 */
class iAuth
{

    // 默认配置
    protected $_config = [];

    public function __construct()
    {

    }

    /**
     * 检查权限
     *
     * @param $uid 认证用户的id
     * @param $name 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
     * @param string $relation 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
     * @return bool 通过验证返回true;失败返回false
     */
    public function check($uid, $name, $relation = 'or')
    {
        if (is_string($name)) {
            $name = strtolower($name);
            if (strpos($name, ',') !== false) {
                $name = explode(',', $name);
            } else {
                $name = array($name);
            }
        }

        $roles = Db::name('admin_role_user')
            ->alias('a')
            ->join('admin_roles b', 'b.id = a.role_id')
            ->where('a.admin_id', $uid)
            ->field('a.role_id, b.access')
            ->select();

        if ($roles) {
            $groups = [];
            $access = '';
            foreach ($roles as $item) {
                $groups[] = $item['role_id'];
                $access .= ',' . $item['access'];
            }

            //if(!Cache::get('admin_access')) Cache::put('admin_access', substr($access, 1), 3600*6);

            if (empty($groups)) return false;

            $rules = Db::name('admin_auth_rule')
                ->alias('a')
                ->whereIn('a.role_id', $groups)
                ->whereIn('a.name', $name)
                ->field('a.name')
                ->select();

            $list = array(); // 保存验证通过的规则名
            foreach ($rules as $rule) {
                if (!empty($rule['condition'])) {
                    // 根据condition进行验证
                    // TODO ...
                    $list[] = strtolower($rule['name']);
                } else {
                    // 只要存在就记录
                    $list[] = strtolower($rule['name']);
                }
            }

            if ($relation == 'or' and !empty($list)) {
                return true;
            }

            $diff = array_diff($name, $list);
            if ($relation == 'and' and empty($diff)) {
                return true;
            }
        }

        return false;
    }

}
